package lifo.GammaTaf.SerieParallel;


import java.util.Arrays;

import java.util.ArrayList;


import lifo.GammaTaf.SerieParallel.SerieParallel.Sharp;

import lifo.GammaTaf.GammaPomset.GammaPomset;
import lifo.GammaTaf.SerieParallel.SerieParallel;

public class SerieParallelToGammaPomset implements VisitorSerieParallel {

	GammaPomset res;

	static public GammaPomset eval(SerieParallel exp) {
		SerieParallelToGammaPomset visitor = new SerieParallelToGammaPomset();
		exp.accepteVisiteur(visitor);
		return visitor.res;
	}

	public void visiteAction(SerieParallel.Action action) {
		res = new GammaPomset.Action(gammaSetAll(1), action.arg, gammaSetAll(1));
	}

	public void visiteSum(SerieParallel.Sum sum) {
		int gammaSet = 0;
		GammaPomset[] arg = new GammaPomset[sum.arg.length];
		for (int i = 0; i < sum.arg.length; i++) {
			sum.arg[i].accepteVisiteur(this);
			arg[i] = res;
			int tmp = gammaSet(res);
			gammaSet = gammaSet < tmp ? tmp : gammaSet;
		}

		boolean[] all = new boolean[gammaSet];
		Arrays.fill(all, true);
		res = new GammaPomset.Sum(new GammaPomset[] {
				new GammaPomset.Action(gammaSetAll(gammaSet), "", gammaSetAll(gammaSet)),
				new GammaPomset.Serie(arg),
				new GammaPomset.Action(gammaSetAll(gammaSet), "", gammaSetAll(gammaSet)) });
	}

	public void visiteStar(SerieParallel.Star star) {
		star.arg.accepteVisiteur(this);
		res = new GammaPomset.Star(res);
	}

	public void visiteSerie(SerieParallel.Serie serie) {
		int gammaSet = 0;
		ArrayList<GammaPomset> arg = new ArrayList<GammaPomset>();
		for (SerieParallel  sp : serie.arg) {
			sp.accepteVisiteur(this);

			int tmp = gammaSet(res);
			gammaSet = gammaSet < tmp ? tmp : gammaSet;

			if (res.getClass() != GammaPomset.Serie.class)
				arg.add(res);
			else {
				for (GammaPomset  spp : ((GammaPomset.Serie)res).arg)
					arg.add(spp);
			}
		}

		for( GammaPomset g: arg)
			setGammaSetAll(g,gammaSet);
		
		res = new GammaPomset.Serie(arg.toArray(new GammaPomset[]{}));
	}

	public void visiteParallel(SerieParallel.Parallel parallel) {
		int gammaSet = 0;
		GammaPomset[] arg = new GammaPomset[3*parallel.arg.length];
		for (int i=0; i< parallel.arg.length; i++) {
			parallel.arg[i].accepteVisiteur(this);
			int tmp = gammaSet(res);
			gammaSet = gammaSet < tmp ? tmp : gammaSet;
			arg[3*i+1] = res;
		}

		/*** A revoir ***/
		
		for (int i=0; i< parallel.arg.length; i++) {
			arg[3*i] = new GammaPomset.Action(gammaSetOne(gammaSet),"", gammaSetOne(gammaSet));
			arg[3*i+2] = new GammaPomset.Action(gammaSetOne(gammaSet+1),"", gammaSetOne(gammaSet+1));
		}

		
		res = new GammaPomset.Serie(arg);

	}

	private static int gammaSet(GammaPomset exp) {
		GammaPomset.Action a;
		if (exp.getClass() == GammaPomset.Action.class)
			a = (GammaPomset.Action) exp;
		else {
			GammaPomset.Serie serie = (GammaPomset.Serie) exp;
			a = (GammaPomset.Action) serie.arg[0];
		}
		return a.pre.length;
	}

	private static void setGammaSetAll(GammaPomset exp, int n) {
		if (exp.getClass() == GammaPomset.Action.class) {
			GammaPomset.Action a = (GammaPomset.Action) exp;
			a.pre = gammaSetAll(n);
			a.post = gammaSetAll(n);
		}
		else {
			SerieParallel.Serie serie = (SerieParallel.Serie) exp;
			GammaPomset.Action a = (GammaPomset.Action) serie.arg[0];
			a.pre = gammaSetAll(n);
			a = (GammaPomset.Action) serie.arg[serie.arg.length];
			a.post = gammaSetAll(n);			
		}
	}

	private static boolean[] gammaSetAll(int n) {
		boolean[] res = new boolean[n];
		Arrays.fill(res, true);
		return res;

	}

	private static boolean[] gammaSetOne(int n) {
		boolean[] res = new boolean[n+1];
		Arrays.fill(res, false);
		res[n] = true;
		return res;
	}

	private static boolean[] gammaSetOne(boolean[] b, int n) {
		boolean[] res = b;
		if (n >= b.length) {
			res = Arrays.copyOf(b, n+1);
		}
		res[n] = true;
		return res;
	}


	public void visiteSharp(Sharp sharp) {
		// TODO Auto-generated method stub
		
	}	
}
